package com.earthea.scaffold.system.service;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.util.IdUtil;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import cn.hutool.jwt.JWT;
import com.earthea.cache.CacheService;
import com.earthea.common.util.JacksonUtils;
import com.earthea.scaffold.common.constant.Constants;
import com.earthea.scaffold.common.enums.CacheEnum;
import com.earthea.scaffold.common.util.ServletUtils;
import com.earthea.scaffold.domain.LoginUser;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Objects;

@Slf4j
@Service
public class TokenService {

    /**
     * 令牌前缀
     */
    private static final String TOKEN_PREFIX = "Bearer ";

    /**
     * 令牌登录uuid
     */
    private static final String LOGIN_USER_KEY = "login_user_key";

    /**
     * 令牌秘钥
     */
    @Value("${app.token.secret}")
    private String secret;

    /**
     * 令牌有效期（默认30分钟）
     */
    @Value("${app.token.expireTime}")
    private int expireTime;

    @Autowired
    private CacheService cacheService;

    /**
     * 根据请求token获取登录用户，用于登录和登出
     *
     * @param request 请求
     * @return 登录用户
     */
    public LoginUser getLoginUser(HttpServletRequest request) {
        // 获取请求携带的令牌
        String token = getToken(request);
        if (StringUtils.isNotEmpty(token)) {
            try {
                JWT jwt = JWT.of(token);
                String uuid = (String) jwt.getPayload(LOGIN_USER_KEY);
                return JacksonUtils.fromJson(cacheService.get(CacheEnum.LOGIN_TOKEN.getCacheKey(uuid)), LoginUser.class);
            } catch (Exception e) {
                log.error("获取用户信息异常: {}", e.getMessage());
            }
        }
        return null;
    }

    /**
     * 更新当前登录用户，用于修改用户信息
     *
     * @param loginUser 登录用户
     */
    public void setLoginUser(LoginUser loginUser) {
        if (Objects.nonNull(loginUser)) {
            String uuid = loginUser.getUuid();
            if (StringUtils.isNotEmpty(uuid)) {
                refreshToken(loginUser);
            }
        }
    }

    /**
     * 删除登录用户，用于退出登录
     *
     * @param uuid uuid
     */
    public void delLoginUser(String uuid) {
        if (StringUtils.isNotEmpty(uuid)) {
            String userKey = CacheEnum.LOGIN_TOKEN.getCacheKey(uuid);
            cacheService.del(userKey);
        }
    }

    /**
     * 创建token，用于登录
     *
     * @param loginUser 登录用户
     * @return token
     */
    public String createToken(LoginUser loginUser) {
        String uuid = IdUtil.fastUUID();
        loginUser.setUuid(uuid);
        UserAgent userAgent = UserAgentUtil.parse(ServletUtils.getRequest().getHeader(HttpHeaders.USER_AGENT));
        loginUser.setLoginIp(ServletUtils.getIpAddr());
        loginUser.setBrowser(userAgent.getBrowser().getName());
        loginUser.setOs(userAgent.getOs().getName());
        refreshToken(loginUser);
        return JWT.create().setPayload(LOGIN_USER_KEY, uuid).setKey(secret.getBytes()).sign();
    }

    /**
     * 刷新token，每次请求
     *
     * @param loginUser 登录用户
     */
    public void verifyToken(LoginUser loginUser) {
        long expireTime = loginUser.getExpireTime();
        long currentTime = System.currentTimeMillis();
        if (expireTime - currentTime <= (10 * DateUtils.MILLIS_PER_MINUTE)) {
            refreshToken(loginUser);
        }
    }

    /**
     * 刷新token
     *
     * @param loginUser 登录用户
     */
    private void refreshToken(LoginUser loginUser) {
        loginUser.setLoginTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
        loginUser.setExpireTime(System.currentTimeMillis() + expireTime * DateUtils.MILLIS_PER_MINUTE);
        // 根据uuid将loginUser缓存
        String uuid = loginUser.getUuid();
        String userKey = CacheEnum.LOGIN_TOKEN.getCacheKey(uuid);
        cacheService.setex(userKey, JacksonUtils.toJson(loginUser), expireTime);
    }

    /**
     * 获取请求token
     *
     * @param request 请求体
     * @return token
     */
    private String getToken(HttpServletRequest request) {
        String token = request.getHeader(HttpHeaders.AUTHORIZATION);
        if (StringUtils.isNotEmpty(token) && token.startsWith(TOKEN_PREFIX)) {
            token = token.replace(TOKEN_PREFIX, "");
        }
        return token;
    }
}
